package com.github.byakkili.bim.core;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import com.github.byakkili.bim.core.cluster.BaseClusterPacket;
import com.github.byakkili.bim.core.cluster.ClusterManager;
import com.github.byakkili.bim.core.support.collection.Topics;
import com.github.byakkili.bim.core.threadpool.ThreadPool;
import lombok.Getter;

import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;

/**
 * B-IM上下文
 *
 * @author Guannian Li
 */
@Getter
public class BimContext {
    /**
     * 服务器ID
     */
    public final String serverId = UUID.randomUUID().toString();
    /**
     * 配置
     */
    private final BimConfiguration config;
    /**
     * 主题连接信息
     */
    private final Topics topics = new Topics();
    /**
     * 命令处理线程池
     */
    private final ExecutorService executor;
    /**
     * 属性
     */
    private final Map<String, Object> attributes = new ConcurrentHashMap<>();

    public BimContext(BimConfiguration config) {
        this.config = config;
        this.executor = Optional.ofNullable(config.getThreadPool()).map(ThreadPool::getExecutor).orElse(null);

        Optional.ofNullable(config.getClusterManager()).ifPresent(cm -> cm.setContext(this));
    }

    /**
     * 发送信息给主题
     *
     * @param topic             主题
     * @param msg               消息
     * @param excludeSessionIds 排除的Session
     */
    public void sendToTopic(String topic, Object msg, String... excludeSessionIds) {
        Set<BimSession> sessions = topics.getSessions(topic);
        CollUtil.emptyIfNull(sessions).forEach(session -> {
            if (!ArrayUtil.contains(excludeSessionIds, session.getId())) {
                session.writeAndFlush(msg);
            }
        });
    }

    /**
     * 发送到集群
     *
     * @param clusterPacket 集群包
     * @return 是否发送成功
     */
    public boolean sendToCluster(BaseClusterPacket clusterPacket) {
        ClusterManager clusterManager = config.getClusterManager();
        if (clusterManager == null) {
            return false;
        }
        clusterPacket.setFromServerId(serverId);
        return clusterManager.send(clusterPacket);
    }

    /**
     * 获取属性
     *
     * @param key 键
     * @return 值
     */
    public Object getAttribute(String key) {
        return attributes.get(key);
    }

    /**
     * 设置属性
     *
     * @param key   键
     * @param value 值
     */
    public void setAttribute(String key, Object value) {
        attributes.put(key, value);
    }

    /**
     * 删除属性
     *
     * @param key 键
     */
    public void removeAttribute(String key) {
        attributes.remove(key);
    }
}
